function [PriorProb, CondKNNTable, CondLabeledRanksTable] = Ddavid_MLkLNN_Training(SampledTrueLabelTraining, SampledOnlyTrueLabelTraining, K, KL, TrainingKNNList, LabeledTrainingKNNList)

% [PriorProb, CondKNNTable, CondLabeledRanksTable] = Ddavid_MLkLNN_Training(SampledTrueLabelTraining, SampledOnlyTrueLabelTraining, K, KL, TrainingKNNList)
%
% <Input>
% SampledTrueLabelTraining: [n*k], the value is {-1, 1}, the sampled labels
%                                  of the training data, n is the number of
%                                  all training data, k is the number of
%                                  labels
% SampledOnlyTrueLabelTraining: [nl*k], the value is {-1, 1}, the sampled
%                                       labels of the labeled training data
%                                       , nl is the number of labeled data
%                                       , k is the number of labels
% K: The K value of KNN, K < n
% KL: The K value of KLNN, K < n
% TrainingKNNList: [n*(n-1)], The KNN List between training points and
%                             other training points (for saving time)
%
% <Output>

TrainingSize = size(SampledTrueLabelTraining, 1);
LabeledTrainingSize = size(SampledOnlyTrueLabelTraining, 1); % The number of the data which have at least one label
LabelSize = size(SampledTrueLabelTraining, 2);

s = 1; % Laplace smoothing

% Training
%%% Computing the TrainingLabeledSize: [1*LabelSize] for all labels and
%%% Prior prob

TrainingLabeledSize = Ddavid_get_training_labeled_size(SampledTrueLabelTraining); % The number of the data with each label
PriorProb = (s + TrainingLabeledSize) / (2 * s + LabeledTrainingSize);

%%% Define features

FKNNRange = K + 1; % 0~K
CondKNNTable = ones(LabelSize, FKNNRange) * s;

FLabeledRanksRange = TrainingSize + 1; % 0~TrainingSize
% LabeledRanksTable = ones(TrainingSize, LabelSize) * (TrainingSize + 1);
CondLabeledRanksTable = ones(LabelSize, FLabeledRanksRange, KL) * s;

for LabelCounter = 1:LabelSize
    SampledTrueLabelTrainingOfSingleLabel = SampledTrueLabelTraining(:, LabelCounter);
    SampledOnlyTrueLabelTrainingOfSingleLabel = SampledOnlyTrueLabelTraining(:, LabelCounter);
    
    % Training
    
    %%% Filter the positive sorted training KNN list with target label and
    %%% transform it to the labeled list
    
    FilteredTrainingKNNLabeledList = Ddavid_get_filtered_knn_labeled_list(SampledTrueLabelTrainingOfSingleLabel, TrainingKNNList);
    FilteredLabeledTrainingKNNLabeledList = Ddavid_get_filtered_knn_labeled_list(SampledOnlyTrueLabelTrainingOfSingleLabel, LabeledTrainingKNNList);
    
    %%% Get feature: KNN
    
    FeaturesKNNTraining = sum(FilteredLabeledTrainingKNNLabeledList(:, 1:K) == 1, 2);
    for FeatureCounter = 1:size(FeaturesKNNTraining, 1);
        CondKNNTable(LabelCounter, FeaturesKNNTraining(FeatureCounter) + 1) = CondKNNTable(LabelCounter, FeaturesKNNTraining(FeatureCounter) + 1) + 1;
    end
    for CondTableCounter = 1:FKNNRange
        CondKNNTable(LabelCounter, CondTableCounter) = CondKNNTable(LabelCounter, CondTableCounter) / (s * FKNNRange + TrainingLabeledSize(LabelCounter));
    end
    
    %%% Get feature: labeled ranks

    for SizeCounter = 1:TrainingLabeledSize(LabelCounter)
        TempList = find(FilteredTrainingKNNLabeledList(SizeCounter, :) == 1);
        TempListSize = TrainingLabeledSize(LabelCounter) - 1; % TempListSize is equal to (the number of instances with the label) - 1
        if(TempListSize > KL)
            TempListSize = KL;
        end
        for RankCounter = 1:TempListSize
            CondLabeledRanksTable(LabelCounter, TempList(RankCounter) + 1, RankCounter) = CondLabeledRanksTable(LabelCounter, TempList(RankCounter) + 1, RankCounter) + 1;
        end
    end
    for RankCounter = 1:KL
        for CondLabeledRanksTableCounter = 1:FLabeledRanksRange
            CondLabeledRanksTable(LabelCounter, CondLabeledRanksTableCounter, RankCounter) = CondLabeledRanksTable(LabelCounter, CondLabeledRanksTableCounter, RankCounter) / (s * FLabeledRanksRange + TrainingLabeledSize(LabelCounter));
        end
    end
end
